#include <iostream>
#include <fstream>
#include <string>
//~ #include <cstdio>
#include <cstring>
//~ #include <cctype>
//~ #include <cmath>
//~ #include <cstdlib>
#include <iomanip>

using namespace std;

#include "tcalendario.h"

// FORMA CANÓNICA
//Constructor por defecto : inicializa dia, mes y anyo a 1 de 1 del 1900 y mensaje a NULL
TCalendario::TCalendario ()
{
    dia=01;
    mes=01;
    anyo=1900;
    string nulo="";
    mensaje = new char[nulo.length()+1];
    strcpy(mensaje,nulo.c_str());
    mensaje[nulo.length()]='\0';
}
//Constructor que inicializa calendario con parámetros pasados
TCalendario::TCalendario(int DiaNuevo, int MesNuevo, int AnyoNuevo, char * Mens)
{
    bool correcto=false;
    if(AnyoNuevo>=1900 && DiaNuevo>0 && MesNuevo>0 && DiaNuevo<32 && MesNuevo<13)
    {
        if(!(AnyoNuevo%4) && (AnyoNuevo%100 || !(AnyoNuevo%400)))
        {
            if(!(MesNuevo%2))
            {
                if(MesNuevo==2)
                {
                    if(DiaNuevo<30)correcto=true;
                }
                else
                {
                    if(DiaNuevo<31)correcto=true;
                }
            }
            else
            {
                correcto=true;
            }
        }
        else
        {
            if(!(MesNuevo%2))
            {
                if(MesNuevo==2)
                {

                    if(DiaNuevo<29)correcto=true;
                }
                else
                {
                    if(DiaNuevo<31)correcto=true;
                }
            }
            else
            {
                correcto=true;
            }
        }
    }
    if(correcto)
    {
        dia=DiaNuevo;
        mes=MesNuevo;
        anyo=AnyoNuevo;
        if(Mens == NULL)
        {
            string nulo="";
            mensaje = new char[nulo.length()+1];
            strcpy(mensaje,nulo.c_str());
        }
        else
        {
            mensaje=new char[strlen(Mens)+1];
            strcpy(mensaje,Mens);
            mensaje[strlen(Mens)]='\0';
        }
    }
    else
    {
        dia=1;
        mes=1;
        anyo=1900;
        string nulo="";
        mensaje = new char[nulo.length()+1];
        strcpy(mensaje,nulo.c_str());
        mensaje[nulo.length()]='\0';
    }
}
//Constructor copia
TCalendario::TCalendario (const TCalendario &nuevoCalendario)
{
    dia=nuevoCalendario.dia;
    mes=nuevoCalendario.mes;
    anyo=nuevoCalendario.anyo;
    if(nuevoCalendario.mensaje == NULL)
    {
        mensaje = NULL;
    }
    else
    {
        mensaje=new char[strlen(nuevoCalendario.mensaje)+1];
        strcpy(mensaje,nuevoCalendario.mensaje);
    }
}
//Destructor
TCalendario::~TCalendario()
{
    dia=1;
    mes=1;
    anyo=1900;
    if(!mensaje)delete[] mensaje;
    string nulo="";
    mensaje = new char[nulo.length()+1];
    strcpy(mensaje,nulo.c_str());
}
// Sobrecarga del operador asignación
TCalendario & TCalendario::operator=(const TCalendario &nuevoCalendario)
{
    if(this!=&nuevoCalendario)
    {
        this->~TCalendario();
        dia=nuevoCalendario.dia;
        mes=nuevoCalendario.mes;
        anyo=nuevoCalendario.anyo;
        if(nuevoCalendario.mensaje == NULL)
        {
            mensaje = NULL;
        }
        else
        {
            mensaje=new char[strlen(nuevoCalendario.mensaje)+1];
            strcpy(mensaje,nuevoCalendario.mensaje);
        }
    }

    return *this;
}
// MÉTODOS
// Sobrecarga del operador SUMA de fecha + un número de dias;
TCalendario TCalendario::operator+(int diasSumar)
{
    TCalendario temporal(*this);
    if(diasSumar>0)
    {
        for(int i=diasSumar;i>0; i--)
        {
            ++temporal;
        }
    }
    return temporal;
}
// Sobrecarga del operador RESTA de fecha - un número de dias;
TCalendario TCalendario::operator-(int diasRestar)
{
    TCalendario temporal(*this);
    if(diasRestar>0)
    {
        for(int i=diasRestar;i>0; i--)
        {
            --temporal;
        }
    }
    return temporal;
}
// Modifica la fecha incrementandola en un dia (con postincremento);
TCalendario TCalendario::operator++(int)const
{
    TCalendario temporal(*this);
    temporal.dia++;
    if(!(temporal.anyo%4) && (temporal.anyo%100 || !(temporal.anyo%400)))
    {
        if(!(temporal.mes%2))
        {
            if(temporal.mes==2)
            {
                if(temporal.dia==30)
                {
                    temporal.dia=1;
                    temporal.mes=3;
                }
            }
            else
            {
                if(temporal.dia==31)
                {
                    temporal.dia=1;
                    if(temporal.mes!=12)
                    {
                        temporal.mes++;
                    }
                    else
                    {
                        temporal.mes=1;
                        temporal.anyo++;
                    }
                }
            }
        }
        else
        {
            if(temporal.dia==32)
            {
                temporal.dia=1;
                temporal.mes++;
            }
        }
    }
    else
    {
        if(!(temporal.mes%2))
        {
            if(temporal.mes==2)
            {
                if(temporal.dia==29)
                {
                    temporal.dia=1;
                    temporal.mes=3;
                }
            }
            else
            {
                if(temporal.dia==31)
                {
                    temporal.dia=1;
                    if(temporal.mes!=12)
                    {
                        temporal.mes++;
                    }
                    else
                    {
                        temporal.mes=1;
                        temporal.anyo++;
                    }
                }
            }
        }
        else
        {
            if(temporal.dia==32)
            {
                temporal.dia=1;
                temporal.mes++;
            }
        }
    }
    return(temporal);
}
// Modifica la fecha incrementandola en un dia (con preincremento);
TCalendario &TCalendario::operator++()
{
    this->dia++;
    if(!(anyo%4) && (anyo%100 || !(anyo%400)))
    {
        if(!(mes%2))
        {
            if(mes==2)
            {
                if(dia==30)
                {
                    this->dia=1;
                    this->mes=3;
                }
            }
            else
            {
                if(dia==31)
                {
                    this->dia=1;
                    if(mes!=12)
                    {
                        this->mes++;
                    }
                    else
                    {
                        this->mes=1;
                        this->anyo++;
                    }
                }
            }
        }
        else
        {
            if(dia==32)
            {
                this->dia=1;
                this->mes++;
            }
        }
    }
    else
    {
        if(!(mes%2))
        {
            if(mes==2)
            {
                if(dia==29)
                {
                    this->dia=1;
                    this->mes=3;
                }
            }
            else
            {
                if(dia==31)
                {
                    this->dia=1;
                    if(mes!=12)
                    {
                        this->mes++;
                    }
                    else
                    {
                        this->mes=1;
                        this->anyo++;
                    }
                }
            }
        }
        else
        {
            if(dia==32)
            {
                this->dia=1;
                this->mes++;
            }
        }
    }
    return *this;
}
// Modifica la fecha decrementándola en un dia (con postdecremento);
TCalendario TCalendario::operator--(int)const
{
    TCalendario temporal(*this);

    temporal.dia--;
    if(!(temporal.anyo%4) && (temporal.anyo%100 || !(temporal.anyo%400)))
    {
        if(temporal.mes%2)
        {
            if(temporal.mes==3)
            {
                if(temporal.dia==0)
                {
                    temporal.dia=29;
                    temporal.mes=2;
                }
            }
            else
            {
                if(temporal.dia==0)
                {
                    temporal.dia=30;
                    if(temporal.mes!=1)
                    {
                        temporal.mes--;
                    }
                    else
                    {
                        temporal.mes=12;
                        temporal.anyo--;
                    }
                }
            }
        }
        else
        {
            if(temporal.dia==0)
            {
                temporal.dia=32;
                temporal.mes--;
            }
        }
    }
    else
    {
        if(temporal.mes%2)
        {
            if(temporal.mes==3)
            {
                if(temporal.dia==0)
                {
                    temporal.dia=28;
                    temporal.mes=2;
                }
            }
            else
            {
                if(temporal.dia==0)
                {
                    temporal.dia=30;
                    if(temporal.mes!=1)
                    {
                        temporal.mes--;
                    }
                    else
                    {
                        temporal.mes=12;
                        temporal.anyo--;
                    }
                }
            }
        }
        else
        {
            if(temporal.dia==0)
            {
                temporal.dia=31;
                temporal.mes--;
            }
        }
    }
    if(temporal.anyo<1900)
    {
        temporal.dia=1;
        temporal.mes=1;
        temporal.anyo=1900;
        if(!mensaje)delete[] temporal.mensaje;
        string nulo="";
        temporal.mensaje = new char[nulo.length()+1];
        strcpy(mensaje,nulo.c_str());
    }
    return temporal;
}
// Modifica la fecha decrementándola en un día (con predecremento);
TCalendario &TCalendario::operator--()
{
    this->dia--;
    if(!(anyo%4) && (anyo%100 || !(anyo%400)))
    {
        if(mes%2)
        {
            if(mes==3)
            {
                if(dia==0)
                {
                    this->dia=29;
                    this->mes=2;
                }
            }
            else
            {
                if(dia==0)
                {
                    this->dia=30;
                    if(mes!=1)
                    {
                        this->mes--;
                    }
                    else
                    {
                        this->mes=12;
                        this->anyo--;
                    }
                }
            }
        }
        else
        {
            if(dia==0)
            {
                this->dia=31;
                this->mes--;
            }
        }
    }
    else
    {
        if(mes%2)
        {
            if(mes==3)
            {
                if(dia==0)
                {
                    this->dia=28;
                    this->mes=2;
                }
            }
            else
            {
                if(dia==0)
                {
                    this->dia=30;
                    if(mes!=1)
                    {
                        this->mes--;
                    }
                    else
                    {
                        this->mes=12;
                        this->anyo--;
                    }
                }
            }
        }
        else
        {
            if(dia==0)
            {
                this->dia=31;
                this->mes--;
            }
        }
    }
    if(anyo<1900)
    {
        dia=1;
        mes=1;
        anyo=1900;
        if(!mensaje)delete[] mensaje;
        string nulo="";
        mensaje = new char[nulo.length()+1];
        strcpy(mensaje,nulo.c_str());
    }
    return *this;
}
// Modifica la fecha
bool TCalendario::ModFecha (int DiaNuevo, int MesNuevo, int AnyoNuevo)
{
    bool correcto=false;
    if(AnyoNuevo>=1900 && DiaNuevo>0 && MesNuevo>0 && DiaNuevo<32 && MesNuevo<13)
    {
        if(!(AnyoNuevo%4) && (AnyoNuevo%100 || !(AnyoNuevo%400)))
        {
            if(!(MesNuevo%2))
            {
                if(MesNuevo==2)
                {
                    if(DiaNuevo<30)correcto=true;
                }
                else
                {
                    if(DiaNuevo<31)correcto=true;
                }
            }
            else
            {
                correcto=true;
            }
        }
        else
        {
            if(!(MesNuevo%2))
            {
                if(MesNuevo==2)
                {
                    if(DiaNuevo<28)correcto=true;
                }
                else
                {
                    if(DiaNuevo<31)correcto=true;
                }
            }
            else
            {
                correcto=true;
            }
        }
    }
    if(correcto)
    {
        dia=DiaNuevo;
        mes=MesNuevo;
        anyo=AnyoNuevo;
    }
    return correcto;
}
// Modifica el mensaje
bool TCalendario::ModMensaje(char *Mens)
{
    if(!mensaje)delete[] mensaje;
    if(Mens!=NULL)
    {
        mensaje=new char[strlen(Mens)+1];
        strcpy(mensaje,Mens);
    }
    else
    {
        //~ mensaje=NULL;
        string nulo="";
        mensaje = new char[nulo.length()+1];
        strcpy(mensaje,nulo.c_str());
    }
    return true;
}
// Sobrecarga del operador igualdad;
bool TCalendario::operator ==(const TCalendario & otroCalendario)const
{
    return(dia==otroCalendario.dia && mes==otroCalendario.mes && anyo==otroCalendario.anyo && !strcmp(mensaje,otroCalendario.mensaje));
}
// Sobrecarga del operador desigualdad;
bool TCalendario::operator !=(const TCalendario & otroCalendario)const
{
    return !(*this==otroCalendario);
}
// Sobrecarga del operador >; (ver ACLARACIÓN sobre ORDENACIÓN)
bool TCalendario::operator>(const TCalendario & otroCalendario)const
{
    bool mayor=false;
    if(anyo>otroCalendario.anyo)mayor=true;
    else if(anyo==otroCalendario.anyo && mes>otroCalendario.mes)mayor=true;
    else if(mes==otroCalendario.mes && dia>otroCalendario.dia)mayor=true;
    else if(dia==otroCalendario.dia && strcmp(otroCalendario.mensaje,mensaje)<0)mayor=true;

    return mayor;
}
// Sobrecarga del operador <; (ver ACLARACIÓN sobre ORDENACIÓN)
bool TCalendario::operator<(const TCalendario &otroCalendario)const
{
    bool menor=false;
    if(anyo<otroCalendario.anyo)menor=true;
    else if(anyo==otroCalendario.anyo && mes<otroCalendario.mes)menor=true;
    else if(mes==otroCalendario.mes && dia<otroCalendario.dia)menor=true;
    else if(dia==otroCalendario.dia && strcmp(mensaje,otroCalendario.mensaje)>0)menor=true;

    return menor;
}
//TCalendario vacío
bool TCalendario::EsVacio()const
{
    return (dia==1 && mes==1 && anyo==1900 && !mensaje);
}
// Devuelve el día del calendario;
int TCalendario::Dia()const{return dia;}
// Devuelve el mes del calendario;
int TCalendario::Mes()const{return mes;}
// Devuelve el año del calendario;
int TCalendario::Anyo()const{return anyo;}
// Devuelve el mensaje del calendario;
char *TCalendario::Mensaje()const{return mensaje;}
//FUNCIONES AMIGAS
// Sobrecarga del operador salida
ostream & operator<<(ostream &os, const TCalendario & calendario)
{
    os << setw(2) << setfill('0');
    os << calendario.Dia() << "/" ;
    os << setw(2) << setfill('0');
    os << calendario.Mes() << "/" ;
    os << calendario.Anyo() << " ";
    if(calendario.Mensaje())os << "\"" << calendario.Mensaje() << "\"";
    else os << "\"\"";
    return os;
}

